package run.microservice.stock.config;

import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.DateUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import run.microservice.stock.utils.ObjectMapperUtil;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 *
 * @author lunfangyu
 */
@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 问题：
     * 使用ResponseBodyAdvice处理统一返回结果时，对于一般的类型都没有问题，当处理字符串类型时，会抛出 xxx.包装类 cannot be cast to java.lang.String 的类型转换的异常
     *
     * 原因：
     * 在ResponseBodyAdvice实现类中debug发现，只有 String 类型的 selectedConverterType 参数值是 org.springframework.http.converter.StringHttpMessageConverter，
     * 而其他数据类型的值是 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
     *
     * 解决方式：
     * 交换MappingJackson2HttpMessageConverter与第一位元素
     * 让返回值类型为String的接口能正常返回包装结果
     *
     * 备注：自定义字典序列化生效也需要把MappingJackson2HttpMessageConverter放在第一位
     * @param converters initially an empty list of converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("调整序列化转换器优先级（重要）");
        for (int i = 0; i < converters.size(); i++) {
            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
                MappingJackson2HttpMessageConverter converter = (MappingJackson2HttpMessageConverter) converters.get(i);
                // 使用自定义的ObjectMapper，以解决Long、BigInt精度丢失、日期格式化等序列化问题，统一返回结果
                converter.setObjectMapper(ObjectMapperUtil.getInstance().getObjectMapper());
                converters.set(i, converters.get(0));
                // 互换位置，把MappingJackson2HttpMessageConverter放在第一位
                converters.set(0, converter);
                break;
            }
        }
    }

    /*
     注意：上面ObjectMapper对日期时间格式化的配置，仅对ResponseBody或者用到Jackson2ObjectMapper进行转换的有效，但是对URL中的参数无效
     因此以下的日期时间格式转换配置，针对用于转换@RequestParam、@PathVariable、@@ModelAttribute 的参数
    */
    /********************************* begin ******************************************/
    /**
     * 文本转换日期
     * 注意：IDEA会建议转换为Lambda写法，但千万不要转换！不要转换！！不要转换！！！
     *      转换为Lambda写法后, 应用启动时会报类型转换错误
     * @return
     */
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String s) {
                return LocalDate.parse(s, DateTimeFormatter.ISO_LOCAL_DATE);
            }
        };
    }
    @Bean
    public Converter<String, LocalTime> localTimeConverter() {
        return new Converter<String, LocalTime>() {
            @Override
            public LocalTime convert(String s) {
                return LocalTime.parse(s, DateTimeFormatter.ISO_LOCAL_TIME);
            }
        };
    }
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String s) {
                return  LocalDateTime.parse(s, DateUtil.DATETIME_FORMATTER);
            }
        };
    }
    /********************************* end ******************************************/
}
